#include "rfid_api.h"
#include "fm1208_app.h"

#if _RFID_FUNCTION_ENABLE_

bool FmcosRats(void)
{
  uint8_t RatsDataSize = 0, RatsDataBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  if (Rats(0x02, 0x50, RatsDataBuff, &RatsDataSize) == true)
    return true;

  return false;
}

bool FmcosEraseCardAllDirector(uint16_t DirectorId)
{
  uint16_t EraseSize = 0, Sw1Sw2 = 0;
  uint8_t EraseDataBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  EraseDataBuff[EraseSize++] = 0x80;
  EraseDataBuff[EraseSize++] = 0x0E;
  EraseDataBuff[EraseSize++] = 0x00;
  EraseDataBuff[EraseSize++] = 0x00;
  EraseDataBuff[EraseSize++] = 0x00;
  EraseDataBuff[EraseSize++] = (uint8_t)((DirectorId & 0xFF00) >> 8);
  EraseDataBuff[EraseSize++] = (uint8_t)(DirectorId & 0x00FF);

  if (APDU_Exchange(EraseDataBuff, (uint8_t)EraseSize, EraseDataBuff, &EraseSize) == true)
  {
    Sw1Sw2 = (EraseDataBuff[EraseSize - 2] << 8) | EraseDataBuff[EraseSize - 1];
    if (Sw1Sw2 == 0x9000)
      return true;
  }

  return false;
}

bool FmcosCreateSubdirectoryDirectory(uint16_t FileIdent, uint16_t FileSize, uint16_t Permission, uint8_t *pFileName, uint8_t NumnerOfName)
{
  uint16_t CreateDfDataSize = 0, Sw1Sw2 = 0;
  uint8_t CreateDfDataBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  CreateDfDataBuff[CreateDfDataSize++] = 0x80;
  CreateDfDataBuff[CreateDfDataSize++] = 0xE0;
  CreateDfDataBuff[CreateDfDataSize++] = (uint8_t)((FileIdent & 0xFF00) >> 8);
  CreateDfDataBuff[CreateDfDataSize++] = (uint8_t)(FileIdent & 0x00FF);
  CreateDfDataBuff[CreateDfDataSize++] = 8 + NumnerOfName;
  CreateDfDataBuff[CreateDfDataSize++] = 0x38;
  CreateDfDataBuff[CreateDfDataSize++] = (uint8_t)((FileSize & 0xFF00) >> 8);
  CreateDfDataBuff[CreateDfDataSize++] = (uint8_t)(FileSize & 0x00FF);
  CreateDfDataBuff[CreateDfDataSize++] = (uint8_t)((Permission & 0xFF00) >> 8);
  CreateDfDataBuff[CreateDfDataSize++] = (uint8_t)(Permission & 0x00FF);
  CreateDfDataBuff[CreateDfDataSize++] = 0x95;
  CreateDfDataBuff[CreateDfDataSize++] = 0xFF;
  CreateDfDataBuff[CreateDfDataSize++] = 0xFF;
  memcpy(&CreateDfDataBuff[CreateDfDataSize], pFileName, NumnerOfName);
  CreateDfDataSize += NumnerOfName;

  if (APDU_Exchange(CreateDfDataBuff, (uint8_t)CreateDfDataSize, CreateDfDataBuff, &CreateDfDataSize) == true)
  {
    Sw1Sw2 = (CreateDfDataBuff[CreateDfDataSize - 2] << 8) | CreateDfDataBuff[CreateDfDataSize - 1];
    if (Sw1Sw2 == 0x9000)
      return true;
  }

  return false;
}

bool FmcosSelectCardDirector(uint16_t DirectorId)
{
  uint16_t SelectDataSize = 0, Sw1Sw2 = 0;
  uint8_t SelectDataBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  SelectDataBuff[SelectDataSize++] = 0x00;
  SelectDataBuff[SelectDataSize++] = 0xA4;
  SelectDataBuff[SelectDataSize++] = 0x00;
  SelectDataBuff[SelectDataSize++] = 0x00;
  SelectDataBuff[SelectDataSize++] = 0x02;
  SelectDataBuff[SelectDataSize++] = (uint8_t)((DirectorId & 0xFF00) >> 8);
  SelectDataBuff[SelectDataSize++] = (uint8_t)(DirectorId & 0xFF);

  if (APDU_Exchange(SelectDataBuff, (uint8_t)SelectDataSize, SelectDataBuff, &SelectDataSize) == true)
  {
    Sw1Sw2 = (SelectDataBuff[SelectDataSize - 2] << 8) | SelectDataBuff[SelectDataSize - 1];
    if (Sw1Sw2 == 0x9000)
      return true;
  }

  return false;
}

bool FmcosEnterDirectoryByFileName(char *FileName)
{
  uint16_t EnterDataSize = 0, Sw1Sw2 = 0;
  uint8_t EnterDataBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  if (FileName != NULL)
  {
    EnterDataBuff[EnterDataSize++] = 0x00;
    EnterDataBuff[EnterDataSize++] = 0xA4;
    EnterDataBuff[EnterDataSize++] = 0x04;
    EnterDataBuff[EnterDataSize++] = 0x00;
    EnterDataBuff[EnterDataSize++] = strlen(FileName);
    memcpy(&EnterDataBuff[EnterDataSize], FileName, strlen(FileName));
    EnterDataSize += strlen(FileName);

    if (APDU_Exchange(EnterDataBuff, (uint8_t)EnterDataSize, EnterDataBuff, &EnterDataSize) == true)
    {
      Sw1Sw2 = (EnterDataBuff[EnterDataSize - 2] << 8) | EnterDataBuff[EnterDataSize - 1];
      if (Sw1Sw2 == 0x9000)
        return true;
    }
  }

  return false;
}

bool FmcosCreateDirectoryKeyFile(uint8_t FileType, uint16_t FileSpace, uint16_t Permission)
{
  uint16_t CreateFileDataSize = 0, Sw1Sw2 = 0;
  uint8_t CreateFileDataBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  CreateFileDataBuff[CreateFileDataSize++] = 0x80;
  CreateFileDataBuff[CreateFileDataSize++] = 0xE0;
  CreateFileDataBuff[CreateFileDataSize++] = 0x00;
  CreateFileDataBuff[CreateFileDataSize++] = 0x00;
  CreateFileDataBuff[CreateFileDataSize++] = 0x07;
  CreateFileDataBuff[CreateFileDataSize++] = FileType;
  CreateFileDataBuff[CreateFileDataSize++] = (uint8_t)((FileSpace & 0xFF00) >> 8);
  CreateFileDataBuff[CreateFileDataSize++] = (uint8_t)(FileSpace & 0x00FF);
  CreateFileDataBuff[CreateFileDataSize++] = (uint8_t)((Permission & 0xFF00) >> 8);
  CreateFileDataBuff[CreateFileDataSize++] = (uint8_t)(Permission & 0x00FF);
  CreateFileDataBuff[CreateFileDataSize++] = 0xFF;
  CreateFileDataBuff[CreateFileDataSize++] = 0xFF;

  if (APDU_Exchange(CreateFileDataBuff, (uint8_t)CreateFileDataSize, CreateFileDataBuff, &CreateFileDataSize) == true)
  {
    Sw1Sw2 = (CreateFileDataBuff[CreateFileDataSize - 2] << 8) | CreateFileDataBuff[CreateFileDataSize - 1];
    if (Sw1Sw2 == 0x9000)
      return true;
  }

  return false;
}

bool FmcosCreateDirectoryKeyValue(uint16_t Permission, uint8_t NumberOfAttempts, uint8_t *pSecretKey)
{
  uint16_t CreateKeyDataSize = 0, Sw1Sw2 = 0;
  uint8_t CreateKeyDataBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  CreateKeyDataBuff[CreateKeyDataSize++] = 0x80;
  CreateKeyDataBuff[CreateKeyDataSize++] = 0xD4;
  CreateKeyDataBuff[CreateKeyDataSize++] = 0x01;
  CreateKeyDataBuff[CreateKeyDataSize++] = 0x00;
  CreateKeyDataBuff[CreateKeyDataSize++] = 0x0D;
  CreateKeyDataBuff[CreateKeyDataSize++] = 0xF9;
  CreateKeyDataBuff[CreateKeyDataSize++] = (uint8_t)((Permission & 0xFF00) >> 8);
  CreateKeyDataBuff[CreateKeyDataSize++] = (uint8_t)(Permission & 0x00FF);
  CreateKeyDataBuff[CreateKeyDataSize++] = 0xAA;
  CreateKeyDataBuff[CreateKeyDataSize++] = (NumberOfAttempts << 8) | NumberOfAttempts;
  memcpy(&CreateKeyDataBuff[CreateKeyDataSize], pSecretKey, 8);
  CreateKeyDataSize += 8;

  if (APDU_Exchange(CreateKeyDataBuff, (uint8_t)CreateKeyDataSize, CreateKeyDataBuff, &CreateKeyDataSize) == true)
  {
    Sw1Sw2 = (CreateKeyDataBuff[CreateKeyDataSize - 2] << 8) | CreateKeyDataBuff[CreateKeyDataSize - 1];
    if (Sw1Sw2 == 0x9000)
      return true;
  }

  return false;
}

bool FmcosGetRandomData(uint8_t SizeOfRandom, uint8_t *pRandomOut)
{
  uint16_t RandomDataSize = 0, Sw1Sw2 = 0;
  uint8_t RandomBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  if ((pRandomOut != NULL) && (SizeOfRandom != 0))
  {
    RandomBuff[RandomDataSize++] = 0x00;
    RandomBuff[RandomDataSize++] = 0x84;
    RandomBuff[RandomDataSize++] = 0x00;
    RandomBuff[RandomDataSize++] = 0x00;
    RandomBuff[RandomDataSize++] = SizeOfRandom;
    if (APDU_Exchange(RandomBuff, (uint8_t)RandomDataSize, RandomBuff, &RandomDataSize) == true)
    {
      Sw1Sw2 = (RandomBuff[RandomDataSize - 2] << 8) | RandomBuff[RandomDataSize - 1];
      if (Sw1Sw2 == 0x9000)
      {
        memcpy(pRandomOut, RandomBuff, SizeOfRandom);
        return true;
      }
    }
  }

  return false;
}

bool FmcosExternalVerification(uint8_t *pAuthenticationKey, uint8_t NumberOfKey)
{
  uint16_t ExternalVerificationDataSize = 0, Sw1Sw2 = 0;
  uint8_t ExternalVerificationBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  if ((pAuthenticationKey != NULL) && (NumberOfKey != 0))
  {
    ExternalVerificationBuff[ExternalVerificationDataSize++] = 0x00;
    ExternalVerificationBuff[ExternalVerificationDataSize++] = 0x82;
    ExternalVerificationBuff[ExternalVerificationDataSize++] = 0x00;
    ExternalVerificationBuff[ExternalVerificationDataSize++] = 0x00;
    ExternalVerificationBuff[ExternalVerificationDataSize++] = NumberOfKey;
    memcpy(&ExternalVerificationBuff[ExternalVerificationDataSize], pAuthenticationKey, NumberOfKey);
    ExternalVerificationDataSize += NumberOfKey;

    if (APDU_Exchange(ExternalVerificationBuff, (uint8_t)ExternalVerificationDataSize, ExternalVerificationBuff, &ExternalVerificationDataSize) == true)
    {
      Sw1Sw2 = (ExternalVerificationBuff[ExternalVerificationDataSize - 2] << 8) | ExternalVerificationBuff[ExternalVerificationDataSize - 1];
      if (Sw1Sw2 == 0x9000)
        return true;
    }
  }

  return false;
}

bool FmcosCreateBinFile(uint16_t FileSize, uint16_t Permission)
{
  uint16_t CreateBinFileDataSize = 0, Sw1Sw2 = 0;
  uint8_t CreateBinFileDataBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  CreateBinFileDataBuff[CreateBinFileDataSize++] = 0x80;
  CreateBinFileDataBuff[CreateBinFileDataSize++] = 0xE0;
  CreateBinFileDataBuff[CreateBinFileDataSize++] = 0x00;
  CreateBinFileDataBuff[CreateBinFileDataSize++] = 0x03;
  CreateBinFileDataBuff[CreateBinFileDataSize++] = 0x07;
  CreateBinFileDataBuff[CreateBinFileDataSize++] = 0x28;
  CreateBinFileDataBuff[CreateBinFileDataSize++] = (uint8_t)((FileSize & 0xFF00) >> 8);
  CreateBinFileDataBuff[CreateBinFileDataSize++] = (uint8_t)(FileSize & 0x00FF);
  CreateBinFileDataBuff[CreateBinFileDataSize++] = (uint8_t)((Permission & 0xFF00) >> 8);
  CreateBinFileDataBuff[CreateBinFileDataSize++] = (uint8_t)(Permission & 0x00FF);
  CreateBinFileDataBuff[CreateBinFileDataSize++] = 0xFF;
  CreateBinFileDataBuff[CreateBinFileDataSize++] = 0xFF;

  if (APDU_Exchange(CreateBinFileDataBuff, (uint8_t)CreateBinFileDataSize, CreateBinFileDataBuff, &CreateBinFileDataSize) == true)
  {
    Sw1Sw2 = (CreateBinFileDataBuff[CreateBinFileDataSize - 2] << 8) | CreateBinFileDataBuff[CreateBinFileDataSize - 1];
    if (Sw1Sw2 == 0x9000)
      return true;
  }

  return false;
}

bool FmcosWriteBinFile(uint16_t WriteOffset, uint8_t *pFileData, uint8_t DataSize)
{
  uint16_t WriteBinFileDataSize = 0, Sw1Sw2 = 0;
  uint8_t WriteBinFileDataBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  WriteBinFileDataBuff[WriteBinFileDataSize++] = 0x00;
  WriteBinFileDataBuff[WriteBinFileDataSize++] = 0xD6;
  WriteBinFileDataBuff[WriteBinFileDataSize++] = (uint8_t)((WriteOffset & 0xFF00) >> 8);
  WriteBinFileDataBuff[WriteBinFileDataSize++] = (uint8_t)(WriteOffset & 0x00FF);
  WriteBinFileDataBuff[WriteBinFileDataSize++] = DataSize;
  memcpy(&WriteBinFileDataBuff[WriteBinFileDataSize], pFileData, DataSize);
  WriteBinFileDataSize += DataSize;

  if (APDU_Exchange(WriteBinFileDataBuff, (uint8_t)WriteBinFileDataSize, WriteBinFileDataBuff, &WriteBinFileDataSize) == true)
  {
    Sw1Sw2 = (WriteBinFileDataBuff[WriteBinFileDataSize - 2] << 8) | WriteBinFileDataBuff[WriteBinFileDataSize - 1];
    if (Sw1Sw2 == 0x9000)
      return true;
  }

  return false;
}

bool FmcosReadBinFile(uint16_t ReadOffset, uint8_t *pDataOut, uint16_t *pSizeOut)
{
  uint16_t ReadBinFileDataSize = 0, Sw1Sw2 = 0;
  uint8_t ReadeBinFileDataBuff[FM1208_OPERATION_DATA_SIZE] = {0};

  ReadeBinFileDataBuff[ReadBinFileDataSize++] = 0x00;
  ReadeBinFileDataBuff[ReadBinFileDataSize++] = 0xB0;
  ReadeBinFileDataBuff[ReadBinFileDataSize++] = (uint8_t)((ReadOffset & 0xFF00) >> 8);
  ReadeBinFileDataBuff[ReadBinFileDataSize++] = (uint8_t)(ReadOffset & 0x00FF);
  ReadeBinFileDataBuff[ReadBinFileDataSize++] = 0x00;
  ReadeBinFileDataBuff[ReadBinFileDataSize++] = 0x00;

  if (APDU_Exchange(ReadeBinFileDataBuff, (uint8_t)ReadBinFileDataSize, ReadeBinFileDataBuff, &ReadBinFileDataSize) == true)
  {
    Sw1Sw2 = (ReadeBinFileDataBuff[ReadBinFileDataSize - 2] << 8) | ReadeBinFileDataBuff[ReadBinFileDataSize - 1];
    if (Sw1Sw2 == 0x9000)
    {
      memcpy(pDataOut, ReadeBinFileDataBuff, ReadBinFileDataSize - 2);
      *pSizeOut = ReadBinFileDataSize - 2;

      return true;
    }
  }

  return false;
}

#endif
